using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Zune.Forms
{
    /// <summary>
    /// The main component of the Zune application.  Only a single Form is supported at this time.
    /// </summary>
    public class Form : Game
    {
        #region Events/Delegates
        /// <summary>
        /// Event handler for Key events.
        /// </summary>
        /// <param name="sender">A Keyboard object.</param>
        /// <param name="key">A KeyboardKey object.</param>
        public delegate void KeyboardEventHandler(object sender, Keys key);
        /// <summary>
        /// Fires when a KeyboardKey is first clicked.
        /// </summary>
        public event KeyboardEventHandler KeyDown;
        /// <summary>
        /// Fires as a KeyboardKey is continuing to be clicked.
        /// </summary>
        public event KeyboardEventHandler KeyPressed;
        /// <summary>
        /// Fires when a KeyboardKey is released.
        /// </summary>
        public event KeyboardEventHandler KeyUp;

        internal event Clipboard.OnClipboardTextChanged ClipboardTextChanged;
        #endregion

        #region Private/Internal Members
        GraphicsDeviceManager _graphics;
        internal SpriteBatch _spriteBatch;
        internal List<Control> _controls = new List<Control>();
        internal List<Control> _sysControls = new List<Control>();
        internal Vector2 _location = new Vector2(0, 0);
        internal Vector2 _size = new Vector2(272, 480);
        internal bool _visible = true;
        internal Color _backColor = Color.CornflowerBlue;
        internal Keyboard _keyboard;
        internal Clipboard _clipboard;
        internal StorageDevice _storageDevice;
        internal bool _drawAlphaBackground = false;
        internal Texture2D _alphaBackground;
        internal MessageBox _messageBox;
        internal Enumerations.DialogResults _previousMessageBoxResult;
        #endregion

        #region Constructors
        /// <summary>
        /// Instantiates a Zune.Forms.Form object.
        /// </summary>
        public Form()
        {
            _graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            _keyboard = new Keyboard(this, true);
            _keyboard.KeyboardClosed += new EventHandler(_keyboard_KeyboardClosed);
            _keyboard.HideKeyboard();
            _clipboard = new Clipboard();
            _clipboard.ClipboardTextChanged += new Clipboard.OnClipboardTextChanged(_clipboard_ClipboardTextChanged);
            _messageBox = new MessageBox(this, true);
            _messageBox.MessageBoxClosed += new MessageBox.OnMessageBoxClosed(_messageBox_MessageBoxClosed);
        }
        #endregion

        #region EventHandlers
        private void _messageBox_MessageBoxClosed(object sender, Enumerations.DialogResults result)
        {
            _drawAlphaBackground = false;
            _previousMessageBoxResult = result;
        }

        private void _keyboard_KeyboardClosed(object sender, EventArgs e)
        {
            _drawAlphaBackground = false;
        }

        protected void _clipboard_ClipboardTextChanged(object sender, bool hasText)
        {
            if (ClipboardTextChanged != null)
                ClipboardTextChanged(sender, hasText);
        }
        #endregion

        #region Overrides
        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            base.Initialize();

            IAsyncResult result = Guide.BeginShowStorageDeviceSelector(null, null);
            while (!result.IsCompleted) { }
            _storageDevice = Guide.EndShowStorageDeviceSelector(result);
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            _spriteBatch = new SpriteBatch(GraphicsDevice);
            foreach (Control ctl in _controls)
                ctl.LoadContent();

            foreach (Control ctl in _sysControls)
                ctl.LoadContent();

            //_alphaBackground = Content.Load<Texture2D>("alphaBackground");
            _alphaBackground = Drawing.CreateRectangle(GraphicsDevice, 272, 480, new Color(Color.LightGray, 175));
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            if (_visible)
            {
                TouchCollection touches = TouchPanel.GetState();

                if (_keyboard._visible || _messageBox._visible)
                {
                    foreach (Control ctl in _sysControls)
                    {
                        if (ctl.Visible && !ctl._cantUpdate)
                            ctl.Update(gameTime, touches);
                    }
                }
                //else
                //{
                if (!_keyboard._visible && !_drawAlphaBackground)
                {
                    foreach (Control ctl in _controls)
                    {
                        if (ctl.Visible && !ctl._cantUpdate)
                            ctl.Update(gameTime, touches);
                    }
                }
                //}

                foreach (Control ctl in _controls)
                {
                    if (ctl.Visible)
                        ctl._cantUpdate = false;
                }
            }
            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            if (_visible)
            {
                GraphicsDevice.Clear(_backColor);
                
                foreach (Control ctl in _controls)
                {
                    if (ctl._visible)
                    {
                        ctl.PreDraw();
                        _spriteBatch.Begin();
                        ctl.Draw(gameTime);
                        DrawBorder(ctl);
                        _spriteBatch.End();
                        ctl.PostDraw();
                    }
                }

                if (_drawAlphaBackground)
                {
                    Viewport vp = new Viewport();
                    vp.X = (Int32)_location.X;
                    vp.Y = (Int32)_location.Y;
                    vp.Width = (Int32)_size.X;
                    vp.Height = (Int32)_size.Y;
                    Viewport _savedViewPort = GraphicsDevice.Viewport;
                    GraphicsDevice.Viewport = vp;

                    _spriteBatch.Begin();
                    _spriteBatch.Draw(_alphaBackground, _location, Color.White);
                    _spriteBatch.End();

                    GraphicsDevice.Viewport = _savedViewPort;
                }

                foreach (Control ctl in _sysControls)
                {
                    if (ctl._visible)
                    {
                        ctl.PreDraw();
                        _spriteBatch.Begin();
                        ctl.Draw(gameTime);
                        DrawBorder(ctl);
                        _spriteBatch.End();
                        ctl.PostDraw();
                    }
                }

                base.Draw(gameTime);
            }
        }

        internal void DrawBorder(Control ctl)
        {
            if (ctl._visible)
            {
                //GraphicsDevice.Clear(BackColor);
                switch (ctl._borderType)
                {
                    case Enumerations.BorderType.BorderSingle:
                        Drawing.DrawBorder(SpriteBatch, ctl._location, ctl._size, ctl._borderColor, ctl._borderWidth);
                        break;
                    case Enumerations.BorderType.Border3D:
                        Drawing.Draw3DBorder(SpriteBatch, ctl._location, ctl._size, ctl._borderColor, ctl._shadowBorderColor, ctl._borderWidth);
                        break;
                }
            }
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Gets the collection of Controls contained in this form.  Use the AddControl method to add new Controls.
        /// </summary>
        public List<Control> Controls
        {
            get { return _controls; }
        }

        /// <summary>
        /// Gets or sets the SpriteBatch.
        /// </summary>
        public SpriteBatch SpriteBatch
        {
            get { return _spriteBatch; }
            set { _spriteBatch = value; }
        }

        /// <summary>
        /// Gets or sets the BackColor of the Form.
        /// </summary>
        public Color BackColor
        {
            get { return _backColor; }
            set { _backColor = value; }
        }

        /// <summary>
        /// Gets or sets whether the Form is Visible.
        /// </summary>
        public new bool Visible
        {
            get { return _visible; }
            set { _visible = value; }
        }

        /// <summary>
        /// Gets the MessageBox DialogResult from the last MessageBox.
        /// </summary>
        public Enumerations.DialogResults MessageBoxDialogResult
        {
            get { return _previousMessageBoxResult; }
        }
        #endregion

        #region Internal Methods
        internal void ShowKeyboard(TextBox textBox)
        {
            _drawAlphaBackground = true;
            _keyboard.ShowKeyboard(textBox);
        }

        internal void HideKeyboard()
        {
            _drawAlphaBackground = false;
            _keyboard.HideKeyboard();
        }

        internal bool IsKeyboardDisplayed
        {
            get { return _keyboard._visible; }
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Addes a new Control the Form.
        /// </summary>
        /// <param name="control"></param>
        public void AddControl(Control control)
        {
            _controls.Add(control);
        }

        /// <summary>
        /// Sets the text value to the Clipboard.
        /// </summary>
        /// <param name="text">The string to set.</param>
        public void SetClipboardText(string text)
        {
            _clipboard.SetText(text);
        }

        /// <summary>
        /// Gets the current text value of the Clipboard.
        /// </summary>
        /// <returns>string</returns>
        public string GetClipboardText()
        {
            return _clipboard.GetText();
        }

        /// <summary>
        /// Queries the Clipboard to see if text exists.
        /// </summary>
        /// <returns>true/false</returns>
        public bool ClipboardContainsText()
        {
            if (string.IsNullOrEmpty(_clipboard.GetText()))
                return false;
            else
                return true;
        }

        /// <summary>
        /// Clears the Clipboard.
        /// </summary>
        public void ClearClipboard()
        {
            _clipboard.SetText(string.Empty);
        }

        /// <summary>
        /// Saves a file to the Zune.
        /// </summary>
        /// <param name="fileName">The name of the file.</param>
        /// <param name="folderName">The name of the folder.</param>
        /// <param name="contents">The file contents.</param>
        public void SaveFile(string fileName, string folderName, string contents)
        {
            Utilities.SaveFile(_storageDevice, fileName, folderName, contents);
        }

        /// <summary>
        /// Gets the text of a file.
        /// </summary>
        /// <param name="fileName">The name of the file.</param>
        /// <param name="folderName">The name of the folder.</param>
        /// <returns>A string value which is the file's contents.</returns>
        public string GetFile(string fileName, string folderName)
        {
            return Utilities.GetFile(_storageDevice, fileName, folderName);
        }

        public void ShowMessageBox(string text, Enumerations.MessageBoxTypes type)
        {
            _drawAlphaBackground = true;
            _messageBox.Show(text, type);
        }
        #endregion
    }
}